//构造函数
function Promise(executor) {
  //为实例对象添加属性
  this.PromiseState = 'pending';
  this.PromiseResult = undefined;
  this.callbacks = [];
  //success 
  let success = value => {
    //判断
    if (this.PromiseState !== 'pending') return;
    //改变状态
    this.PromiseState = 'fulfilled';
    //改变结果值
    this.PromiseResult = value;
    //执行成功的回调
    this.callbacks.forEach(obj => {
      //执行成功的回调
      obj.ok();
    })
  }

  //fail
  let fail = reason => {
    //判断状态是否为 pending
    if (this.PromiseState !== 'pending') return;
    //改变状态
    this.PromiseState = 'rejected';
    //改变结果值
    this.PromiseResult = reason;
    //执行失败的回调
    this.callbacks.forEach(obj => {
      //执行失败的回调
      obj.ng();
    })
  }

  try {
    //执行 执行器函数
    executor(success, fail);
  } catch (e) {
    //改变 promise 实例对象的状态为失败
    fail(e);
  }
}

//原型对象中添加 then 方法
Promise.prototype.then = function (onFulfilled, onRejected) {
  return new Promise((resolve, reject) => {
    //封装函数
    let callback = (type) => {
      try {
        //调用回调函数, 获得返回值
        let res = type(this.PromiseResult);
        if (res instanceof Promise) {
          //如果是一个 promise 实例对象 根据 promise 决定 then 的返回值
          res.then(v => {
            resolve(v);
          }, r => {
            reject(r);
          });
        } else {
          // 如果不是 promise   成功
          resolve(res);
        }
      } catch (e) {
        reject(e);
      }
    }
    //判断实例对象的状态是否为成功
    if (this.PromiseState === 'fulfilled') {
      callback(onFulfilled);
    }
    //判断实例对象的状态是否为失败
    if (this.PromiseState === 'rejected') {
      callback(onRejected);
    }
    //判断 pending 状态
    if (this.PromiseState === 'pending') {
      //将回调函数保存在实例对象身上
      this.callbacks.push({
        ok: function () {
          callback(onFulfilled);
        },
        ng: function () {
          callback(onRejected);
        }
      });
    }
  })
}

/**
 * 1. 声明构造函数, 添加执行器函数的形参
 * 2. 添加原型上的 then 方法, 并且添加两个形参
 * 3. 执行器函数是一个同步回调, 所以在 Promise 构造函数中直接调用 executor
 * 4. 执行 executor 传入两个实参, 并声明两个函数 success 与 fail
 * 5. resolve(success) 函数的作用: 1. 改变状态  2. 改变值
 * 6. 注意 success 函数的 this 指向
 * 7. then 方法中对状态进行判断, 根据状态执行对应的回调函数即可
 * 8. 使用 try...catch 对 executor 的执行进行包裹, 如果抛出错误, 则执行 reject 改变为失败状态
 * 9. 在 success 和 fail 函数中添加检测, 如果状态为 pending 则返回, 保证状态只能修改一次
 */

/**
 * 异步任务执行回调的流程: 
 * 1. 在实例身上添加 callbacks 属性, 值为数组
 * 2. 在 then 方法中检测 pending 状态, 如果是 pending 状态则将回调函数保存在 callbacks 属性上
 * 3. 在 success 和 fail 函数中添加回调函数执行的代码, 遍历 callbacks 属性, 然后执行状态对应的回调函数
 */